package com.easylinkin.linkappapi.mechanical.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easylinkin.linkappapi.circuit.dto.AlarmTypeCount;
import com.easylinkin.linkappapi.circuit.dto.RailGiveAlarmTypeConfigEnum;
import com.easylinkin.linkappapi.circuit.entity.RailGiveAlarmTypeConfig;
import com.easylinkin.linkappapi.circuit.entity.RailGiveSystemAlarm;
import com.easylinkin.linkappapi.circuit.mapper.RailGiveAlarmTypeConfigMapper;
import com.easylinkin.linkappapi.circuit.service.IRailGiveSystemAlarmService;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.common.utils.DateUtil;
import com.easylinkin.linkappapi.common.utils.message.SendMessageUtil;
import com.easylinkin.linkappapi.crane.dto.CraneDTO;
import com.easylinkin.linkappapi.crane.entity.*;
import com.easylinkin.linkappapi.crane.mapper.CraneBusinessRecordMapper;
import com.easylinkin.linkappapi.crane.mapper.CraneOperationAreaMapper;
import com.easylinkin.linkappapi.crane.mapper.CraneVerticalProtectionAreaMapper;
import com.easylinkin.linkappapi.crane.mapper.CraneWorkRecordMapper;
import com.easylinkin.linkappapi.crane.service.ICraneVerticalProtectionAreaService;
import com.easylinkin.linkappapi.device.constant.DeviceConstant;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.service.DeviceService;
import com.easylinkin.linkappapi.mechanical.entity.*;
import com.easylinkin.linkappapi.mechanical.mapper.EquipmentLocationDataMapper;
import com.easylinkin.linkappapi.mechanical.mapper.MechanicalMapper;
import com.easylinkin.linkappapi.mechanical.mapper.MechanicalWorkRecordMapper;
import com.easylinkin.linkappapi.mechanical.service.CraneSafeMonitorService;
import com.easylinkin.linkappapi.mechanical.service.IEquipmentLocationService;
import com.easylinkin.linkappapi.mechanical.service.IMechanicalService;
import com.easylinkin.linkappapi.mechanical.util.CraneUtil;
import com.easylinkin.linkappapi.openapi.dto.DatapushDTO;
import com.easylinkin.linkappapi.project.entity.ProjectPoint;
import com.easylinkin.linkappapi.project.service.IProjectPointService;
import com.easylinkin.linkappapi.roster.entity.RailLinkappRosterPersonnel;
import com.easylinkin.linkappapi.roster.mapper.RailLinkappRosterPersonnelMapper;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.tenant.entity.LinkappTenant;
import com.easylinkin.linkappapi.tenant.mapper.LinkappTenantMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CraneSafeMonitorServiceImpl implements CraneSafeMonitorService {

    /**
     * 告警短信推送模板
     */
    private static final String SMS_ALARM_CODE_REMINDER_PROCESSING = "SMS_490090449";

    @Autowired
    private LinkappUserContextProducer linkappUserContextProducer;
    @Autowired
    private LinkappTenantMapper linkappTenantMapper;
    @Autowired
    private IProjectPointService pointService;
    @Autowired
    private MechanicalMapper mechanicalMapper;
    @Autowired
    private CraneOperationAreaMapper craneOperationAreaMapper;
    @Autowired
    private RailGiveAlarmTypeConfigMapper giveAlarmTypeConfigMapper;
    @Autowired
    private IMechanicalService mechanicalService;
    @Autowired
    private IRailGiveSystemAlarmService railGiveSystemAlarmService;
    @Autowired
    private IEquipmentLocationService equipmentLocationService;
    @Autowired
    private ICraneVerticalProtectionAreaService craneVerticalProtectionAreaService;
    @Autowired
    private SendMessageUtil sendMessageUtil;
    @Autowired
    private CraneVerticalProtectionAreaMapper craneVerticalProtectionAreaMapper;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private CraneBusinessRecordMapper craneBusinessRecordMapper;
    @Autowired
    private RailLinkappRosterPersonnelMapper railLinkappRosterPersonnelMapper;
    @Autowired
    private EquipmentLocationDataMapper equipmentLocationDataMapper;
    @Autowired
    private CraneWorkRecordMapper craneWorkRecordMapper;

    @Override
    public Map<String, Long> todayInfringementLimit() {
        // {"beidouCount": 0, "totalCount": 0, "warningCount": 0}
        Map<String, Long> todayInfringementLimit = new HashMap<>();
        long beidouCount = 0l;
        long totalCount = 0l;
        long warningCount = 0l;
        String tenantId = linkappUserContextProducer.getTenantId();
        // 查询所有工位
//        List<Mechanical> mechanicalList = mechanicalMapper.selectList(new LambdaQueryWrapper<Mechanical>()
//               .eq(Mechanical::getTenantId, tenantId)
//               .eq(Mechanical::getType, "5"));
        Mechanical query = new Mechanical();
        query.setTenantId(tenantId);
        query.setType("5");
        List<Mechanical> mechanicalList = mechanicalMapper.listPage(query);
        if (CollectionUtils.isNotEmpty(mechanicalList)) {
            for (Mechanical mechanical : mechanicalList) {
                List<MechanicalRefDevice> refDeviceList = mechanical.getRefDeviceList();
                if (CollectionUtils.isNotEmpty(refDeviceList)) {
                    beidouCount += refDeviceList.stream().filter(refDevice -> 2 == refDevice.getDeviceType()).count();
                }
                String mechanicalId = mechanical.getId();
                LambdaQueryWrapper<CraneBusinessRecord> qwBusinessRecord = new LambdaQueryWrapper<>();
                qwBusinessRecord.eq(CraneBusinessRecord::getTenantId, tenantId);
                qwBusinessRecord.eq(CraneBusinessRecord::getMechanicalId, mechanicalId);
                qwBusinessRecord.orderByDesc(CraneBusinessRecord::getCreateTime);
                qwBusinessRecord.last("limit 1");
                CraneBusinessRecord craneBusinessRecord = craneBusinessRecordMapper.selectOne(qwBusinessRecord);
                if (craneBusinessRecord != null) {
                    if (craneBusinessRecord.getAlarmDumpPrevention() == 1 || craneBusinessRecord.getAlarmIntrusionPrevention() == 1) {
                        warningCount++;
                    }
                }
            }
            totalCount = mechanicalList.size();
        }
        todayInfringementLimit.put("beidouCount", beidouCount);
        todayInfringementLimit.put("totalCount", totalCount);
        todayInfringementLimit.put("warningCount", warningCount);
        return todayInfringementLimit;
    }

    @Override
    public IPage<CraneDTO> listPage(RequestModel<Mechanical> requestModel) {
        String tenantId = linkappUserContextProducer.getTenantId();
        requestModel.getCustomQueryParams().setType("5");
        requestModel.getCustomQueryParams().setIsRefMainDevice(true);
        IPage<Mechanical> page = mechanicalMapper.listPage(requestModel.getPage(), requestModel.getCustomQueryParams());
        IPage<CraneDTO> craneDTOPage = new Page<>();
        craneDTOPage.setTotal(page.getTotal());
        craneDTOPage.setPages(page.getPages());
        craneDTOPage.setSize(page.getSize());
        craneDTOPage.setCurrent(page.getCurrent());
        craneDTOPage.setRecords(bulidDtoList(linkappUserContextProducer.getTenantId(), page.getRecords()));
        return craneDTOPage;
    }

    @Override
    public List<CraneDTO> queryMechanical() {
        String tenantId = linkappUserContextProducer.getTenantId();
        Mechanical mechanical = new Mechanical();
        mechanical.setTenantId(tenantId);
        mechanical.setType("5");
        List<Mechanical> mechanicalList = mechanicalMapper.listPage(mechanical);
        if (CollectionUtils.isEmpty(mechanicalList)) {
            return Collections.emptyList();
        }
        List<CraneDTO> craneDTOList = bulidDtoList(tenantId, mechanicalList);
        return craneDTOList;
    }

    private List<CraneDTO> bulidDtoList(String tenantId, List<Mechanical> mechanicalList) {
        List<CraneDTO> craneDTOList = new ArrayList<>();
        for (Mechanical mechanical : mechanicalList) {
            String mechanicalId = mechanical.getId();
            CraneDTO craneDTO = new CraneDTO();
            BeanUtils.copyProperties(mechanical, craneDTO);
            //查询总吊重和总次数
            Double totalWeight = craneBusinessRecordMapper.getTotalWeight(tenantId, mechanicalId);
            Long totalHoistingTimes = craneBusinessRecordMapper.getTotalHoistingTimes(tenantId, mechanicalId);
            craneDTO.setTotalWeight(totalWeight != null ? totalWeight : 0.0);
            craneDTO.setTotalHoistingTimes(totalHoistingTimes != null ? totalHoistingTimes : 0L);

            // 最新业务记录
            LambdaQueryWrapper<CraneBusinessRecord> qwBusinessRecord = new LambdaQueryWrapper<>();
            qwBusinessRecord.eq(CraneBusinessRecord::getTenantId, tenantId);
            qwBusinessRecord.eq(CraneBusinessRecord::getMechanicalId, mechanicalId);
            qwBusinessRecord.orderByDesc(CraneBusinessRecord::getCreateTime);
            qwBusinessRecord.last("limit 1");
            CraneBusinessRecord craneBusinessRecord = craneBusinessRecordMapper.selectOne(qwBusinessRecord);
            if (craneBusinessRecord != null) {
                craneDTO.setCraneBusinessRecord(craneBusinessRecord);
            }
            // 查询设备
            Device device = mechanicalService.queryDeviceByMechanicalIdAndType(mechanicalId, "1");
            craneDTO.setDevice(device);
            EquipmentLocationData equipmentLocationData = this.getEquipmentLocationData(tenantId, mechanical.getId());
            if (equipmentLocationData != null) {
                EquipmentLocation equipmentLocation = new EquipmentLocation();
                equipmentLocation.setEquipmentLng(equipmentLocationData.getLocationLng());
                equipmentLocation.setEquipmentLat(equipmentLocationData.getLocationLat());
                craneDTO.setEquipmentLocation(equipmentLocation);
            }
            // 查询北斗设备信息
            Device beidouDevice = mechanicalService.queryDeviceByMechanicalIdAndType(mechanicalId, "2");
            craneDTO.setBeidouDevice(beidouDevice);
            // 查询作业保护区
            List<CraneOperationArea> operationAreas = craneOperationAreaMapper.selectByMechanicalId(mechanicalId);
            craneDTO.setOperationAreaList(operationAreas);
            // 查询垂直保护区
            List<CraneVerticalProtectionArea> verticalProtectionAreaList = getCraneVerticalProtectionAreaList(tenantId);
            if (CollectionUtils.isNotEmpty(verticalProtectionAreaList) && equipmentLocationData!= null) {
                for (CraneVerticalProtectionArea protectionArea : verticalProtectionAreaList) {
                    // 计算垂直距离
                    if (StrUtil.isNotEmpty(protectionArea.getLocation()) && StrUtil.isNotEmpty(equipmentLocationData.getLocationLat())
                            && StrUtil.isNotEmpty(equipmentLocationData.getLocationLng())) {

                        double[] distanceResult = CraneUtil.calculateClosestPointOnLine(equipmentLocationData.getLocationLng(), equipmentLocationData.getLocationLat(), protectionArea.getLocation());
                        double[] middlePoint = {distanceResult[0], distanceResult[1]};
                        protectionArea.setDistance(distanceResult[2]);
                        protectionArea.setMiddlePoint(middlePoint);
                    }
                }
            }
            craneDTO.setVerticalProtectionAreaList(verticalProtectionAreaList);
            boolean isAlarm = false;
            if (device != null && StrUtil.isNotEmpty(device.getCode())) {
                // 查询最近未处理的告警
                LambdaQueryWrapper<RailGiveSystemAlarm> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(RailGiveSystemAlarm::getTenantId, tenantId);
                queryWrapper.eq(RailGiveSystemAlarm::getCategory, "1");
                queryWrapper.eq(RailGiveSystemAlarm::getRefId, mechanical.getId());
                queryWrapper.eq(RailGiveSystemAlarm::getStatus, 0);
                queryWrapper.last("limit 1");
                // 查询最近的所有告警
                queryWrapper.orderByDesc(RailGiveSystemAlarm::getCreateTime);
                List<RailGiveSystemAlarm> list = railGiveSystemAlarmService.list(queryWrapper);
                if (CollectionUtils.isNotEmpty(list)) {
                    craneDTO.setNewlestAlarm(list.get(0));
                    isAlarm = true;
                }
            }
            craneDTO.setAlarmFlag(isAlarm);
            // 最近侵限告警
            boolean isLimitAlarm = false;
            if (device != null && StrUtil.isNotEmpty(device.getCode())) {
                // 查询最近未处理的告警
                LambdaQueryWrapper<RailGiveSystemAlarm> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(RailGiveSystemAlarm::getTenantId, tenantId);
                queryWrapper.eq(RailGiveSystemAlarm::getCategory, "1");
                queryWrapper.eq(RailGiveSystemAlarm::getRefId, mechanical.getId());
                queryWrapper.in(RailGiveSystemAlarm::getAlarmType, Arrays.asList(
                        RailGiveAlarmTypeConfigEnum.AlarmType_17.getType(),
                        RailGiveAlarmTypeConfigEnum.AlarmType_21.getType(),
                        RailGiveAlarmTypeConfigEnum.AlarmType_22.getType(),
                        RailGiveAlarmTypeConfigEnum.AlarmType_23.getType()
                        ));
                queryWrapper.eq(RailGiveSystemAlarm::getStatus, 0);
                // 查询最近的所有告警
                queryWrapper.orderByDesc(RailGiveSystemAlarm::getCreateTime);
                List<RailGiveSystemAlarm> list = railGiveSystemAlarmService.list(queryWrapper);
                if (CollectionUtils.isNotEmpty(list)) {
                    RailGiveSystemAlarm newlestLimitAlarm = null;
                    if (list.size() == 1) {
                        newlestLimitAlarm = list.get(0);
                    } else {
                        newlestLimitAlarm = getNewestLimitAlarm(list);
                    }
                    craneDTO.setNewlestLimitAlarm(newlestLimitAlarm);
                    isLimitAlarm = true;
                }
            }
            craneDTO.setLimitAlarmFlag(isLimitAlarm);
            // 司机信息
            List<String> driverIds = craneDTO.getDriverIds();
            if (CollectionUtils.isNotEmpty(driverIds)) {
                LambdaQueryWrapper<RailLinkappRosterPersonnel> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(RailLinkappRosterPersonnel::getTenantId, tenantId);
                queryWrapper.in(RailLinkappRosterPersonnel::getId, driverIds);
                List<RailLinkappRosterPersonnel> driverList = railLinkappRosterPersonnelMapper.selectList(queryWrapper);
                craneDTO.setDriverList(driverList);
            }
            craneDTOList.add(craneDTO);
        }
        return craneDTOList;
    }

    private RailGiveSystemAlarm getNewestLimitAlarm(List<RailGiveSystemAlarm> list) {
        // 顺序 施工防侵限告警21>防倾倒侵限告警22>距离安全限界告警17>机械离开作业区域告警23 按照顺序排序取一条
        List<RailGiveSystemAlarm> limitAlarmList = list.stream().filter(alarm ->
                alarm.getAlarmType().equals(RailGiveAlarmTypeConfigEnum.AlarmType_21.getType())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(limitAlarmList)) {
            return limitAlarmList.get(0);
        } else {
            List<RailGiveSystemAlarm> limitAlarmList2 = list.stream().filter(alarm ->
                    alarm.getAlarmType().equals(RailGiveAlarmTypeConfigEnum.AlarmType_22.getType())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(limitAlarmList2)) {
                return limitAlarmList2.get(0);
            } else {
                List<RailGiveSystemAlarm> limitAlarmList3 = list.stream().filter(alarm ->
                        alarm.getAlarmType().equals(RailGiveAlarmTypeConfigEnum.AlarmType_17.getType())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(limitAlarmList3)) {
                    return limitAlarmList3.get(0);
                } else {
                    List<RailGiveSystemAlarm> limitAlarmList4 = list.stream().filter(alarm ->
                            alarm.getAlarmType().equals(RailGiveAlarmTypeConfigEnum.AlarmType_23.getType())).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(limitAlarmList4)) {
                        return limitAlarmList4.get(0);
                    }
                }
            }
        }
        return null;
    }

    @Override
    public List<CraneTree> queryCraneTree() {
        List<CraneTree> craneTreeList = new ArrayList<>();
        String tenantId = linkappUserContextProducer.getTenantId();
        LinkappTenant linkappTenant = linkappTenantMapper.getById(tenantId);

        // 1.根节点-项目名称
        CraneTree root = new CraneTree();
        root.setId(tenantId);
        root.setName(linkappTenant.getPlatformProjectName());
        root.setType("project");
        craneTreeList.add(root);
        // 2.查询所有工点
        LambdaQueryWrapper<ProjectPoint> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectPoint::getTenantId, linkappTenant.getId());
        List<ProjectPoint> projectPointList = pointService.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(projectPointList)) {
            for (ProjectPoint projectPoint : projectPointList) {
                CraneTree craneTree = new CraneTree();
                String workPointId = projectPoint.getId();
                craneTree.setId(workPointId);
                craneTree.setName(projectPoint.getPointName());
                craneTree.setType("point");
                craneTree.setPid(tenantId);
                craneTreeList.add(craneTree);
                // 3.根据工点查询绑定机械-机械绑定主机
                List<Mechanical> mechanicalList = mechanicalMapper.selectMechanicalByWorkPointId(workPointId, "5");
                if (CollectionUtils.isEmpty(mechanicalList)) {
                    continue;
                }
                for (Mechanical mechanical : mechanicalList) {
                    List<MechanicalRefDevice> refDeviceList = mechanical.getRefDeviceList();
                    if (CollectionUtils.isEmpty(refDeviceList)) {
                        continue;
                    }
                    refDeviceList = refDeviceList.stream().filter(refDevice -> refDevice.getDeviceType() == 1).collect(Collectors.toList());
                    if (CollectionUtils.isEmpty(refDeviceList)) {
                        continue;
                    }
                    CraneTree deviceTree = new CraneTree();
                    String mechanicalId = mechanical.getId();
                    deviceTree.setId(mechanicalId);
                    deviceTree.setName(mechanical.getName());
                    deviceTree.setType("crane");
                    deviceTree.setPid(workPointId);
                    deviceTree.setTruckCrane(mechanical);
                    // 查询自身防护区
                    List<CraneOperationArea> operationAreas = craneOperationAreaMapper.selectByMechanicalId(mechanicalId);
                    deviceTree.setPreserveAreaList(operationAreas);
                    craneTreeList.add(deviceTree);
                }
            }
        }
        return craneTreeList;
    }

    @Override
    public void datapushHandler(DatapushDTO datapushDTO) {
        // 流水处理流程
        JSONObject data = datapushDTO.getData();
        // String deviceCode = datapushDTO.getDevice_id();
        //将查询逻辑放入主线程
        Device device = datapushDTO.getDevice_data_latest();
        if (!DeviceConstant.RailwayDeviceType.CRANE_TRUCK_MONITOR.getDescription().contains(device.getDeviceUnit().getDeviceTypeName())) {
            return;
        }
        String tenantId = device.getTenantId();
        // 查询项目名称
        LinkappTenant linkappTenant = linkappTenantMapper.getById(tenantId);
        if (Objects.isNull(linkappTenant)) {
            return;
        }
        String platformProjectName = linkappTenant.getPlatformProjectName();

        // 1.查询机械
        Mechanical mechanical = mechanicalService.queryMechanicalByDeviceCode(device.getId(), tenantId);
        if (Objects.isNull(mechanical)) {
            return;
        }
        // 消息类型 1 - 业务数据  2 - 工作数据
        Integer alarmType = data.getInteger("msg_type");
        // 非业务数据直接返回
        if (alarmType == null) {
            return;
        }
        if (alarmType == 2) {
            // 业务数据
            CraneWorkRecord craneWorkRecord = CraneWorkRecord.builder()
                    .tenantId(tenantId)
                    .mechanicalId(mechanical.getId())
                    .deviceId(device.getId())
                    .deviceCode(device.getCode())
                    .deviceName(device.getName())
                    .workStartTime(data.getDate("work_start_time"))
                    .workEndTime(data.getDate("work_end_time"))
                    .maxWeight(data.getBigDecimal("max_weight"))
                    .maxInclination(data.getBigDecimal("max_inclination"))
                    .maxWindSpeed(data.getBigDecimal("max_wind_speed"))
                    .maxArmHeight(data.getBigDecimal("max_arm_height"))
                    .uploadTime(data.getDate("upload_time"))
                    .createTime(new Date())
                    .modifyTime(new Date())
                    .build();
            craneWorkRecordMapper.insert(craneWorkRecord);
            return;
        }

        // 2.记录业务数据
        CraneBusinessRecord craneBusinessRecord = CraneBusinessRecord.builder()
                .tenantId(tenantId)
                .mechanicalId(mechanical.getId())
                .deviceId(device.getId())
                .deviceCode(device.getCode())
                .deviceName(device.getName())
                .workStartTime(data.getDate("work_start_time"))
                .workEndTime(data.getDate("work_end_time"))
                .armForce(data.getBigDecimal("arm_force"))
                .bigArmLen(data.getBigDecimal("big_arm_len"))
                .levelX(data.getBigDecimal("level_x"))
                .levelY(data.getBigDecimal("level_y"))
                .windSpeed(data.getBigDecimal("wind_speed"))
                .rotation(data.getBigDecimal("rotation"))
                .pitch(data.getBigDecimal("pitch"))
                .moment(data.getBigDecimal("moment"))
                .weight(data.getBigDecimal("weight"))
                .inclination(data.getBigDecimal("inclination"))
                .windLevel(data.getBigDecimal("wind_level"))
                .armHeight(data.getBigDecimal("arm_height"))
                .workHour(data.getBigDecimal("work_hour"))
                .idlingHour(data.getBigDecimal("idling_hour"))
                .workTotalHour(data.getBigDecimal("work_total_hour"))
                .hoistingTimes(data.getInteger("hoisting_times"))
                .createTime(new Date())
                .modifyTime(new Date())
                .build();

        // 3. 告警触发
        // 3.1 查询配置
        // 告警总状态
        Integer alarmState = 0;
        LambdaQueryWrapper<RailGiveAlarmTypeConfig> objectQueryWrapper = new LambdaQueryWrapper<>();
        objectQueryWrapper.eq(RailGiveAlarmTypeConfig::getTenantId, tenantId);
        objectQueryWrapper.eq(RailGiveAlarmTypeConfig::getEnabled, 0);
        objectQueryWrapper.eq(RailGiveAlarmTypeConfig::getCategory, "1");
        List<RailGiveAlarmTypeConfig> railGiveAlarmTypeConfig = giveAlarmTypeConfigMapper.selectList(objectQueryWrapper);
        if (CollectionUtil.isNotEmpty(railGiveAlarmTypeConfig)) {
            List<RailGiveAlarmTypeConfig> configList = new ArrayList<>();
            Map<String, List<RailGiveAlarmTypeConfig>> configMap = railGiveAlarmTypeConfig.stream().collect(Collectors.groupingBy(RailGiveAlarmTypeConfig::getType));
//            // 取每一类的最大值触发
//            for (String type : configMap.keySet()) {
//                List<RailGiveAlarmTypeConfig> list = configMap.get(type);
//                RailGiveAlarmTypeConfig maxConfig = list.stream().max(Comparator.comparing(RailGiveAlarmTypeConfig::getLevel)).orElse(null);
//                configList.add(maxConfig);
//            }
//            // 3.告警触发
//            for (RailGiveAlarmTypeConfig config : configList) {
//                String type = config.getType();
//
//                RailGiveAlarmTypeConfigEnum enumType = RailGiveAlarmTypeConfigEnum.getEnum(type);
//                Double threshValue = config.getThreshValue();
//                String field = config.getFieids();
//                Double value = data.getDouble(field);
//                switch (enumType) {
//                    case AlarmType_8:// 风速告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value > threshValue) {
//                            String content = "当前风速达到" + value + "m/s，超安全值，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_8, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmWindSpeed(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmWindSpeed(0);
//                        }
//                        break;
//                    case AlarmType_9:// 俯仰角告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value > threshValue) {
//                            String content = "当前俯仰角为" + value + "°，超安全值，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_9, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmPitch(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmPitch(0);
//                        }
//                        break;
//                    case AlarmType_10: // 力矩告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value > threshValue) {
//                            String content = "当前力矩为" + value + "t· m，超安全值，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_10, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmMoment(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmMoment(0);
//                        }
//                        break;
//                    case AlarmType_11: // 主钩吊重告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value > threshValue) {
//                            String content = "当前主钩吊重为" + value + "t，超安全值，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_11, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmWeight(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmWeight(0);
//                        }
//                        break;
//                    case AlarmType_12: // 大臂长度告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value > threshValue) {
//                            String content = "当前大臂长度为" + value + " m，超安全值，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_12, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmMoment(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmMoment(0);
//                        }
//                        break;
//                    case AlarmType_13: // 水平度X告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value > threshValue) {
//                            String content = "当前水平度x为" + value + "°，超安全值，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_13, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmLevelX(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmLevelX(0);
//                        }
//                        break;
//                    case AlarmType_14: // 水平度Y告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value > threshValue) {
//                            String content = "当前水平度Y为" + value + "°，超安全值，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_14, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmLevelY(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmLevelY(0);
//                        }
//                        break;
//                    case AlarmType_15: // 回转告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value > threshValue) {
//                            String content = "当前回转为" + value + "°，超安全值，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_15, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmRotation(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmRotation(0);
//                        }
//                        break;
//                    case AlarmType_16: // 力臂告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value < threshValue) {
//                            String content = "当前作业半径为" + value + " m，超计划值，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_16, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmArmForce(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmArmForce(0);
//                        }
//                        break;
//                    case AlarmType_17: // 安全限界告警
//                        Double arm_force = data.getDouble("arm_force");
//                        if (Objects.isNull(arm_force)) {
//                            break;
//                        }
//                        // 以吊车圆心为起点，计算垂直到的侵限保护区距离如果小于安全限界距离，则触发告警
//                        Integer alarmSafeLimit = generateProtectionAreaAlarm(tenantId, platformProjectName, arm_force, device, mechanical, config, RailGiveAlarmTypeConfigEnum.AlarmType_21, "当前距安全限界距离为{distance}m，超安全值，请注意");
//                        craneBusinessRecord.setAlarmSafeLimit(alarmSafeLimit);
//                        alarmState = alarmSafeLimit;
//                        break;
//                    case AlarmType_18: // 作业展臂最不利工况可起重吊重告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value > threshValue) {
//                            String content =  "当前主钩吊重为" + value + "t，超最不利工况可起重吊重值，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_18, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmWeightLimit(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmWeightLimit(0);
//                        }
//                        break;
//                    case AlarmType_19: // 最大臂长告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value > threshValue) {
//                            String content = "当前大臂长度为" + value + " m，超安全值，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_19, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmBigArmLenLimit(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmBigArmLenLimit(0);
//                        }
//                        break;
//                    case AlarmType_20: // 倾倒告警
//                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
//                            break;
//                        }
//                        if (value > threshValue) {
//                            String content = "当前存在倾倒风险，请注意";
//                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_20, config, content, platformProjectName);
//                            craneBusinessRecord.setAlarmInclination(1);
//                            alarmState = 1;
//                        } else { // 取消告警
//                            cancelAlarm(device, mechanical, config);
//                            craneBusinessRecord.setAlarmInclination(0);
//                        }
//                        break;
//                    case AlarmType_21: // 施工防侵限告警
//                        Double arm_force1 = data.getDouble("arm_force");
//                        if (Objects.isNull(arm_force1)) {
//                            break;
//                        }
//                        // 以吊车圆心为圆心，力臂为半径画圆的实心圆区域是否进入了侵限保护区，如果进入则判定为施工防侵限
//                        // 吊车的定位 到 侵限保护区 的距离
//                        Integer alarmIntrusionPrevention = generateProtectionAreaAlarm(tenantId, platformProjectName, arm_force1, device, mechanical, config, RailGiveAlarmTypeConfigEnum.AlarmType_21, "作业入侵安全限界，请注意");
//                        craneBusinessRecord.setAlarmIntrusionPrevention(alarmIntrusionPrevention);
//                        alarmState = alarmIntrusionPrevention;
//                        break;
//                    case AlarmType_22: // 防倾倒侵限告警
//                        Double big_arm_len = data.getDouble("big_arm_len");
//                        if (Objects.isNull(big_arm_len)) {
//                            break;
//                        }
//                        // 以吊车圆心为圆心，大臂长度为半径画虚线圆的区域是否进入了侵限保护区，若侵入则判定为防倾倒侵限；
//                        // 根据大臂长度，北斗定位，计算各个距离侵限区距离，并产生告警
//                        Integer alarmDumpPrevention = generateProtectionAreaAlarm(tenantId, platformProjectName, big_arm_len, device, mechanical, config, RailGiveAlarmTypeConfigEnum.AlarmType_22, "有防倾倒侵入安全限界风险，请注意");
//                        craneBusinessRecord.setAlarmDumpPrevention(alarmDumpPrevention);
//                        alarmState = alarmDumpPrevention;
//                        break;
//                    default:
//                        break;
//                }
//            }

            // 新的处理逻辑：按type分类，根据实际值选择合适的告警等级
            for (String type : configMap.keySet()) {
                List<RailGiveAlarmTypeConfig> list = configMap.get(type);
                RailGiveAlarmTypeConfigEnum enumType = RailGiveAlarmTypeConfigEnum.getEnum(type);
                if (enumType == null) {
                    continue;
                }

                // 根据不同告警类型选择合适的阈值配置
                RailGiveAlarmTypeConfig selectedConfig = null;

                if (enumType == RailGiveAlarmTypeConfigEnum.AlarmType_17 ||
                    enumType == RailGiveAlarmTypeConfigEnum.AlarmType_21 ||
                    enumType == RailGiveAlarmTypeConfigEnum.AlarmType_22) {
                    // 特殊处理的告警类型：使用generateProtectionAreaAlarm方法，固定获取特定字段
                    // AlarmType_17和AlarmType_21使用arm_force，AlarmType_22使用big_arm_len
                    String fixedField = null;
                    if (enumType == RailGiveAlarmTypeConfigEnum.AlarmType_17 ||
                        enumType == RailGiveAlarmTypeConfigEnum.AlarmType_21) {
                        fixedField = "arm_force";
                    } else if (enumType == RailGiveAlarmTypeConfigEnum.AlarmType_22) {
                        fixedField = "big_arm_len";
                    }

                    Double value = data.getDouble(fixedField);
                    if (value == null) {
                        continue;
                    }

                    // 这些告警类型有自己的复杂判断逻辑，直接选择等级最高的配置
                    selectedConfig = list.stream()
                        .max(Comparator.comparing(config -> {
                            String level = config.getLevel();
                            return level != null ? Integer.parseInt(level) : 0;
                        }))
                        .orElse(null);
                } else {
                    // 其他告警类型：使用配置中的字段名获取实际值
                    String field = list.get(0).getFieids();
                    if (field == null) {
                        continue;
                    }
                    Double value = data.getDouble(field);
                    if (value == null) {
                        continue;
                    }

                    if (enumType == RailGiveAlarmTypeConfigEnum.AlarmType_16) {
                        // 力臂告警：value < 阈值时触发，选择大于实际值的最小阈值
                        // 例如：value=3, 阈值[1,4,8] -> 选择阈值4（因为3<4会触发告警，且4是最小的可触发阈值）
                        selectedConfig = list.stream()
                            .filter(config -> config.getThreshValue() != null && config.getThreshValue() > value)
                            .min(Comparator.comparing(config -> {
                                // 按阈值排序，取最小的阈值（最接近实际值但大于实际值的）
                                return config.getThreshValue();
                            }))
                            .orElse(null);
                    } else {
                        // 其他告警：value > 阈值时触发，选择小于实际值的最大阈值
                        // 例如：value=6, 阈值[1,5,7] -> 选择阈值5（因为6>5会触发告警，且5是最大的可触发阈值）
                        selectedConfig = list.stream()
                            .filter(config -> config.getThreshValue() != null && config.getThreshValue() < value)
                            .max(Comparator.comparing(config -> {
                                // 按阈值排序，取最大的阈值（最接近实际值但小于实际值的）
                                return config.getThreshValue();
                            }))
                            .orElse(null);
                    }
                }

                if (selectedConfig != null) {
                    configList.add(selectedConfig);
                }else if (CollectionUtil.isNotEmpty(list)){
                    //取第一个
                    configList.add(list.get(0));
                }
            }

            // 3.告警触发
            for (RailGiveAlarmTypeConfig config : configList) {
                String type = config.getType();

                RailGiveAlarmTypeConfigEnum enumType = RailGiveAlarmTypeConfigEnum.getEnum(type);
                Double threshValue = config.getThreshValue();
                String field = config.getFieids();
                Double value = data.getDouble(field);
                switch (enumType) {
                    case AlarmType_8:// 风速告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value > threshValue) {
                            String content = "当前风速达到" + value + "m/s，超安全值，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_8, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmWindSpeed(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmWindSpeed(0);
                        }
                        break;
                    case AlarmType_9:// 俯仰角告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value > threshValue) {
                            String content = "当前俯仰角为" + value + "°，超安全值，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_9, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmPitch(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmPitch(0);
                        }
                        break;
                    case AlarmType_10: // 力矩告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value > threshValue) {
                            String content = "当前力矩为" + value + "t· m，超安全值，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_10, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmMoment(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmMoment(0);
                        }
                        break;
                    case AlarmType_11: // 主钩吊重告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value > threshValue) {
                            String content = "当前主钩吊重为" + value + "t，超安全值，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_11, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmWeight(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmWeight(0);
                        }
                        break;
                    case AlarmType_12: // 大臂长度告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value > threshValue) {
                            String content = "当前大臂长度为" + value + " m，超安全值，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_12, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmMoment(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmMoment(0);
                        }
                        break;
                    case AlarmType_13: // 水平度X告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value > threshValue) {
                            String content = "当前水平度x为" + value + "°，超安全值，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_13, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmLevelX(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmLevelX(0);
                        }
                        break;
                    case AlarmType_14: // 水平度Y告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value > threshValue) {
                            String content = "当前水平度Y为" + value + "°，超安全值，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_14, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmLevelY(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmLevelY(0);
                        }
                        break;
                    case AlarmType_15: // 回转告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value > threshValue) {
                            String content = "当前回转为" + value + "°，超安全值，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_15, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmRotation(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmRotation(0);
                        }
                        break;
                    case AlarmType_16: // 力臂告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value < threshValue) {
                            String content = "当前作业半径为" + value + " m，超计划值，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_16, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmArmForce(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmArmForce(0);
                        }
                        break;
                    case AlarmType_17: // 安全限界告警
                        Double arm_force = data.getDouble("arm_force");
                        if (Objects.isNull(arm_force)) {
                            break;
                        }
                        // 以吊车圆心为起点，计算垂直到的侵限保护区距离如果小于安全限界距离，则触发告警
                        Integer alarmSafeLimit = generateProtectionAreaAlarm(tenantId, platformProjectName, arm_force, device, mechanical, config, RailGiveAlarmTypeConfigEnum.AlarmType_21, "当前距安全限界距离为{distance}m，超安全值，请注意");
                        craneBusinessRecord.setAlarmSafeLimit(alarmSafeLimit);
                        alarmState = alarmSafeLimit;
                        break;
                    case AlarmType_18: // 作业展臂最不利工况可起重吊重告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value > threshValue) {
                            String content =  "当前主钩吊重为" + value + "t，超最不利工况可起重吊重值，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_18, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmWeightLimit(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmWeightLimit(0);
                        }
                        break;
                    case AlarmType_19: // 最大臂长告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value > threshValue) {
                            String content = "当前大臂长度为" + value + " m，超安全值，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_19, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmBigArmLenLimit(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmBigArmLenLimit(0);
                        }
                        break;
                    case AlarmType_20: // 倾倒告警
                        if (Objects.isNull(value) || Objects.isNull(threshValue)) {
                            break;
                        }
                        if (value > threshValue) {
                            String content = "当前存在倾倒风险，请注意";
                            triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_20, config, content, platformProjectName);
                            craneBusinessRecord.setAlarmInclination(1);
                            alarmState = 1;
                        } else { // 取消告警
                            cancelAlarm(device, mechanical, config);
                            craneBusinessRecord.setAlarmInclination(0);
                        }
                        break;
                    case AlarmType_21: // 施工防侵限告警
                        Double arm_force1 = data.getDouble("arm_force");
                        if (Objects.isNull(arm_force1)) {
                            break;
                        }
                        // 以吊车圆心为圆心，力臂为半径画圆的实心圆区域是否进入了侵限保护区，如果进入则判定为施工防侵限
                        // 吊车的定位 到 侵限保护区 的距离
                        Integer alarmIntrusionPrevention = generateProtectionAreaAlarm(tenantId, platformProjectName, arm_force1, device, mechanical, config, RailGiveAlarmTypeConfigEnum.AlarmType_21, "作业入侵安全限界，请注意");
                        craneBusinessRecord.setAlarmIntrusionPrevention(alarmIntrusionPrevention);
                        alarmState = alarmIntrusionPrevention;
                        break;
                    case AlarmType_22: // 防倾倒侵限告警
                        Double big_arm_len = data.getDouble("big_arm_len");
                        if (Objects.isNull(big_arm_len)) {
                            break;
                        }
                        // 以吊车圆心为圆心，大臂长度为半径画虚线圆的区域是否进入了侵限保护区，若侵入则判定为防倾倒侵限；
                        // 根据大臂长度，北斗定位，计算各个距离侵限区距离，并产生告警
                        Integer alarmDumpPrevention = generateProtectionAreaAlarm(tenantId, platformProjectName, big_arm_len, device, mechanical, config, RailGiveAlarmTypeConfigEnum.AlarmType_22, "有防倾倒侵入安全限界风险，请注意");
                        craneBusinessRecord.setAlarmDumpPrevention(alarmDumpPrevention);
                        alarmState = alarmDumpPrevention;
                        break;
                    default:
                        break;
                }
            }
            updateDeviceAlarmStatus(device);
        }
        // 4.保存业务数据
        craneBusinessRecord.setAlarmState(alarmState);
        craneBusinessRecordMapper.insert(craneBusinessRecord);
    }

    // 侵限告警
    public Integer generateProtectionAreaAlarm(String tenantId, String platformProjectName, Double threshValue, Device device, Mechanical mechanical, RailGiveAlarmTypeConfig config, RailGiveAlarmTypeConfigEnum typeConfigEnum, String content) {
        Integer result = 0;
        String mechanicalId = mechanical.getId();
        EquipmentLocationData equipmentLocationData = getEquipmentLocationData(tenantId, mechanicalId);
        List<CraneVerticalProtectionArea> protectionAreaList = getCraneVerticalProtectionAreaList(device.getTenantId());
        // 1.查询吊车的定位
        Boolean isTriggered = true;
        if (equipmentLocationData == null) {
            isTriggered = false;
        }
        // 2.查询启用的侵限保护区列表
        if (CollectionUtils.isEmpty(protectionAreaList)) {
            isTriggered = false;
        }
        if (isTriggered) {
            String HHmmss = cn.hutool.core.date.DateUtil.format(new Date(), DatePattern.NORM_TIME_PATTERN);
            // 根据时间段过滤
            for (CraneVerticalProtectionArea protectionArea : protectionAreaList) {
                List<WorkTime> workTimeList = protectionArea.getWorkTimeList();
                // 判断HHmmss 在WorkTime 之间
                boolean hHmmssInHHmmssRange = CraneUtil.isHHmmssInHHmmssRangeList(HHmmss, workTimeList);
                // 计算垂直距离
                double[] distanceResult = CraneUtil.calculateClosestPointOnLine(equipmentLocationData.getLocationLng(), equipmentLocationData.getLocationLat(), protectionArea.getLocation());
                double distance = distanceResult[2];
                // distance 四舍五入保留两位小数
                distance = new BigDecimal(distance).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                content = content.replace("{distance}", String.valueOf(distance));
                // 产生告警
                if (hHmmssInHHmmssRange && distance < threshValue) {
                    triggerAlarm(device, mechanical, typeConfigEnum, config, content, platformProjectName);
                    // 修改保护区状态
                    protectionArea.setAlarmFlag(true);
                    result = 1;
                } else {
                    // 取消告警
                    cancelAlarm(device, mechanical, config);
                    // 修改保护区状态
                    protectionArea.setAlarmFlag(false);
                }
                craneVerticalProtectionAreaMapper.updateById(protectionArea);
            }
        }
        return result;
    }

    // 触发告警
    @Override
    public void triggerAlarm(Device device, Mechanical mechanical, RailGiveAlarmTypeConfigEnum alarmType, RailGiveAlarmTypeConfig config, String content, String platformProjectName) {
        // 查询同类型告警是否已存在
        Integer deduplicationTime = config.getDeduplicationTime();
        String configType = config.getType();
        String deviceCode = device.getCode();
        String mechanicalName = mechanical.getName();
        String mechanicalId = mechanical.getId();
        boolean isTriggered = true;
        if (!Objects.isNull(deduplicationTime)) {
            LambdaQueryWrapper<RailGiveSystemAlarm> qw = buildAlarmQueryWrapper(device, config, mechanicalId);
            qw.last("limit 1");
            List<RailGiveSystemAlarm> list = railGiveSystemAlarmService.list(qw);
            // 判断时间间隔
            if (CollectionUtils.isNotEmpty(list)) {
                RailGiveSystemAlarm lastAlarm = list.get(0);
                Date lastAlarmTime = lastAlarm.getCreateTime();
                long interval = cn.hutool.core.date.DateUtil.between(lastAlarmTime, new Date(), DateUnit.MINUTE);
                if (interval < deduplicationTime) {
                    // 机械code(监测设备deviceCode) 在时间间隔(deduplicationTime)内已有告警，不再触发
                    log.info("机械【{}】在时间间隔【{}】内已有告警，不再触发", mechanicalName + "(" + deviceCode + ")", deduplicationTime);
                    isTriggered = false;
                }
            }
        }
        if (isTriggered) {
            RailGiveSystemAlarm nowAlarm = new RailGiveSystemAlarm();
            nowAlarm.setRefId(mechanicalId);
            nowAlarm.setDeviceCode(deviceCode);
            nowAlarm.setCreateTime(new Date());
            nowAlarm.setTestingItem(mechanicalName);
            nowAlarm.setAlarmType(configType);
            nowAlarm.setLevel(config.getLevel());
            nowAlarm.setTenantId(device.getTenantId());
            //生成告警
            nowAlarm.setStatus(0);
            nowAlarm.setContent(content);
            String textmsg = getTextMsg(platformProjectName, DateUtil.getYYYYMMDDHHMMSSDate(nowAlarm.getCreateTime()), config.getText(), StringUtils.isEmpty(device.getName()) ? device.getCode() : device.getName());
            nowAlarm.setPushContent(textmsg);
            nowAlarm.setCategory(config.getCategory());
            //保存告警记录
            railGiveSystemAlarmService.save(nowAlarm);
            //判断是否发送短信
            String pushMeth = config.getPushMeth();
            if (StrUtil.isNotEmpty(pushMeth) && pushMeth.contains("2")){
                //发送短信通知
                if (!StringUtils.isEmpty(config.getPushUserPhones())){
                    String[] phones = config.getPushUserPhones().split(",");
                    for (String phoneNumber:phones){
                        if (!StringUtils.isEmpty(phoneNumber)){
                            JSONObject param = new JSONObject();
                            param.put("projectName", platformProjectName);
                            param.put("deviceName", mechanical.getName());
                            param.put("alarmTime", DateUtil.getYYYYMMDDHHMMSSDate(nowAlarm.getCreateTime()));
                            param.put("alarmType", config.getText());
                            sendMessageUtil.sendSms(phoneNumber,SMS_ALARM_CODE_REMINDER_PROCESSING,param.toString());
                        }
                    }
                }
            }
        }
    }

    // 取消告警
    public void cancelAlarm(Device device, Mechanical mechanical, RailGiveAlarmTypeConfig config) {
        String mechanicalId = mechanical.getId();
        // 查询最近的所有告警
        List<RailGiveSystemAlarm> list = railGiveSystemAlarmService.list(buildAlarmQueryWrapper(device, config, mechanicalId));
        if (CollectionUtils.isNotEmpty(list)) {
            // 全部改成已处理
            for (RailGiveSystemAlarm alarm : list) {
                alarm.setStatus(1);
                alarm.setModifier("1");
                alarm.setModifyTime(new Date());
                alarm.setHandleId("1");
                alarm.setHandleName("系统");
                alarm.setHandleRest(0);
                alarm.setHandleResp("指标已正常，告警自动取消");
                railGiveSystemAlarmService.updateById(alarm);
            }
        }
    }

    private LambdaQueryWrapper<RailGiveSystemAlarm> buildAlarmQueryWrapper(Device device, RailGiveAlarmTypeConfig config, String mechanicalId) {
        LambdaQueryWrapper<RailGiveSystemAlarm> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RailGiveSystemAlarm::getTenantId, device.getTenantId());
        queryWrapper.eq(RailGiveSystemAlarm::getAlarmType, config.getType());
        queryWrapper.eq(RailGiveSystemAlarm::getDeviceCode, device.getCode());
        queryWrapper.eq(RailGiveSystemAlarm::getRefId, mechanicalId);
        queryWrapper.eq(RailGiveSystemAlarm::getStatus, 0);
        queryWrapper.orderByDesc(RailGiveSystemAlarm::getCreateTime);
        return queryWrapper;
    }

    // 项目名称+xx机械于+时间（年月日时分秒）发生+告警类型，请及时处理！
    //例如：台安至黑山高速涉铁工程中B6783M 汽车起重机于2025-04-24 13:43:27发生大臂长度告警，请及时处理!
    // {#projectName#}中{#deviceName#}于{#alarmTime#}发生{#alarmType#}，请及时处理！
    private String getTextMsg(String platformProjectName, String alarmTime, String alarmType, String deviceName) {
        return platformProjectName + "中" + deviceName + "于" + alarmTime + "发生" + alarmType + "，请及时处理！";
    }

    private EquipmentLocationData getEquipmentLocationData(String tenantId, String mechanicalId) {
        LambdaQueryWrapper<EquipmentLocationData> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(EquipmentLocationData::getTenantId, tenantId);
        queryWrapper1.eq(EquipmentLocationData::getEquipmentId, mechanicalId);
        // 时间倒序
        queryWrapper1.orderByDesc(EquipmentLocationData::getCreateTime);
        queryWrapper1.last("limit 1");
        List<EquipmentLocationData> equipmentLocationDataList1 = equipmentLocationDataMapper.selectList(queryWrapper1);
        if (CollectionUtils.isNotEmpty(equipmentLocationDataList1)) {
            return equipmentLocationDataList1.get(0);
        }
        return null;
    }

    private List<CraneVerticalProtectionArea> getCraneVerticalProtectionAreaList(String tenantId) {
        LambdaQueryWrapper<CraneVerticalProtectionArea> queryWrapper21 = new LambdaQueryWrapper<>();
        queryWrapper21.eq(CraneVerticalProtectionArea::getTenantId, tenantId);
        queryWrapper21.eq(CraneVerticalProtectionArea::getEnabledFlag, 1);
        queryWrapper21.orderByDesc(CraneVerticalProtectionArea::getCreateTime);
        List<CraneVerticalProtectionArea> list1 = craneVerticalProtectionAreaService.list(queryWrapper21);
        return list1;
    }

    @Override
    public void onlineStateChange(Device device, Integer onlineState) {
        String tenantId = device.getTenantId();
        // 查询项目名称
        LinkappTenant linkappTenant = linkappTenantMapper.getById(tenantId);
        if (Objects.isNull(linkappTenant)) {
            return;
        }
        String platformProjectName = linkappTenant.getPlatformProjectName();
        // 1.查询机械
        Mechanical mechanical = mechanicalService.queryMechanicalByDeviceCode(device.getId(), tenantId);
        if (Objects.isNull(mechanical)) {
            return;
        }
        // 记录工作记录
        recordWorkRecord(device, mechanical, onlineState);
        //查询配置
        LambdaQueryWrapper<RailGiveAlarmTypeConfig> objectQueryWrapper = new LambdaQueryWrapper<>();
        objectQueryWrapper.eq(RailGiveAlarmTypeConfig::getTenantId, tenantId);
        objectQueryWrapper.eq(RailGiveAlarmTypeConfig::getType, RailGiveAlarmTypeConfigEnum.AlarmType_7.getType());
        List<RailGiveAlarmTypeConfig> railGiveAlarmTypeConfig = giveAlarmTypeConfigMapper.selectList(objectQueryWrapper);
        if (Objects.isNull(railGiveAlarmTypeConfig)) {
            log.error("项目{}未查询到配置信息, 无法触发告警", platformProjectName);
            return;
        }
        RailGiveAlarmTypeConfig config = railGiveAlarmTypeConfig.get(0);
        if (config.getEnabled() == 0) {
            // 2.设备离线产生告警
            if (onlineState == 0) {
                String content = "设备离线，请及时查看";
                triggerAlarm(device, mechanical, RailGiveAlarmTypeConfigEnum.AlarmType_7, config, content, platformProjectName);
            }
            // 3.设备上线取消告警
            if (onlineState == 1) { // 取消告警
                cancelAlarm(device, mechanical, config);
            }
        } else {
            // 未启用，取消告警
            cancelAlarm(device, mechanical, config);
        }
        // 4.更新设备总告警状态
        updateDeviceAlarmStatus(device);
    }

    private void recordWorkRecord(Device device, Mechanical mechanical, Integer onlineState) {
        if (!DeviceConstant.RailwayDeviceType.BEIDOU_LOCATION.getDescription().contains(device.getDeviceUnit().getDeviceTypeName())) {
            return;
        }
        if (onlineState == 1) {
            recordStartWorkRecord(mechanical);
        } else {
            recordEndWorkRecord(mechanical);
        }
    }

    @Override
    public void updateDeviceAlarmStatus(Device device) {
        Integer status = 0;
        LambdaQueryWrapper<RailGiveSystemAlarm> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RailGiveSystemAlarm::getTenantId, device.getTenantId());
        queryWrapper.eq(RailGiveSystemAlarm::getDeviceCode, device.getCode());
        queryWrapper.eq(RailGiveSystemAlarm::getStatus, 0);
        queryWrapper.orderByDesc(RailGiveSystemAlarm::getCreateTime);
        int count = railGiveSystemAlarmService.count(queryWrapper);
        if (count > 0) {
            status = 1;
        } else {
            status = 0;
        }
        deviceService.updateStatusById(device.getId(), status);
    }

    @Autowired
    private MechanicalWorkRecordMapper mechanicalWorkRecordMapper;

    // 记录机械开始工作记录
    public void recordStartWorkRecord(Mechanical mechanical) {
        MechanicalWorkRecord mechanicalWorkRecord = new MechanicalWorkRecord();
        mechanicalWorkRecord.setTenantId(mechanical.getTenantId());
        mechanicalWorkRecord.setMechanicalId(mechanical.getId());
        mechanicalWorkRecord.setStartTime(new Date());
        mechanicalWorkRecord.setCreateId(1l);
        mechanicalWorkRecord.setCreateTime(new Date());
        mechanicalWorkRecord.setModifyTime(new Date());
        mechanicalWorkRecordMapper.insert(mechanicalWorkRecord);
    }

    // 记录机械结束记录
    public void recordEndWorkRecord(Mechanical mechanical) {
        LambdaQueryWrapper<MechanicalWorkRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MechanicalWorkRecord::getTenantId, mechanical.getTenantId());
        queryWrapper.eq(MechanicalWorkRecord::getMechanicalId, mechanical.getId());
        queryWrapper.orderByDesc(MechanicalWorkRecord::getCreateTime);
        List<MechanicalWorkRecord> list = mechanicalWorkRecordMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        Date date = new Date();
        // 计算工作时长 单位：秒
        long workTime = date.getTime() - list.get(0).getStartTime().getTime();
        MechanicalWorkRecord lastRecord = list.get(0);
        lastRecord.setEndTime(date);
        lastRecord.setWorkTime(Integer.parseInt(String.valueOf(workTime / 1000)));
        lastRecord.setModifyId(1l);
        lastRecord.setModifyTime(date);
        mechanicalWorkRecordMapper.updateById(lastRecord);
    }

    @Override
    public Map<String, Object> todayAlarmClassification() {
        Integer totalCount = 0;
        Date startTime = cn.hutool.core.date.DateUtil.beginOfDay(new Date());
        Date endTime = cn.hutool.core.date.DateUtil.endOfDay(new Date());
        Integer otherCount = 0;
        Integer alarmInclinationCount = 0;
        List<AlarmTypeCount> resultList = new ArrayList<>();
        List<AlarmTypeCount> alarmTypeCounts = railGiveSystemAlarmService.alarmTypeCount("1", null, startTime, endTime);
        // （统计显示前三名的告警类型和占比、剩余类型都归为其他）
        if (CollectionUtils.isNotEmpty(alarmTypeCounts)) {
            Integer count = 0;
            for (AlarmTypeCount alarmTypeCount : alarmTypeCounts) {
                if (RailGiveAlarmTypeConfigEnum.AlarmType_20.getType().equals(alarmTypeCount.getAlarmType())) {
                    alarmInclinationCount = alarmTypeCount.getCount();
                }
                totalCount += alarmTypeCount.getCount();
                if (count < 3) {
                    resultList.add(alarmTypeCount);
                    count++;
                } else {
                    otherCount += alarmTypeCount.getCount();
                }
            }
            if (otherCount > 0) {
                AlarmTypeCount alarmTypeCount = new AlarmTypeCount();
                alarmTypeCount.setAlarmType("-1");
                alarmTypeCount.setName("其他");
                alarmTypeCount.setCount(otherCount);
                resultList.add(alarmTypeCount);
            }
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("totalCount", totalCount);
        resultMap.put("alarmInclinationCount",  alarmInclinationCount);
        resultMap.put("alarmTypeCounts", resultList);
        return resultMap;
    }

    @Override
    public boolean hasLeftAreaAlarmDevice(Long areaId, String mechanicalId) {
        // 根据区域查机械
        CraneOperationArea craneOperationArea = craneOperationAreaMapper.queryById(areaId);
        if (craneOperationArea == null) {
            return false;
        }
        List<Mechanical> mechanicalList = craneOperationArea.getMechanicalList();
        if (CollectionUtil.isEmpty(mechanicalList)) {
            return false;
        }
        List<String> mechanicalIds = mechanicalList.stream().map(Mechanical::getId).collect(Collectors.toList());
        LambdaQueryWrapper<RailGiveSystemAlarm> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RailGiveSystemAlarm::getTenantId, craneOperationArea.getTenantId());
        queryWrapper.in(RailGiveSystemAlarm::getRefId, mechanicalIds);
        queryWrapper.eq(RailGiveSystemAlarm::getStatus, 0);
        // 离开作业区域告警
        queryWrapper.eq(RailGiveSystemAlarm::getAlarmType, RailGiveAlarmTypeConfigEnum.AlarmType_23.getType());
        queryWrapper.orderByDesc(RailGiveSystemAlarm::getCreateTime);
        int count = railGiveSystemAlarmService.count(queryWrapper);
        if (count > 0) {
            return true;
        }
        return false;
    }
}
